/**/
#include <cstdio>
#include <SFML/Graphics.hpp>
#include "../common.h"

using namespace sf;
using namespace std;

const int ESPACE_TS      = 5;
const int NB_MAX_PER_LIG = 8;
const int EP_LIG         = 3;

const int TS_SEL  = 1;
const int MAP_SEL = 0;

int currLayer = L_SOL;

typedef pair<Sprite,int> sprite_and_indice;

int x_start, y_start;

sprite_and_indice m_map[N_LAYER][MAP_DIM_MAX][MAP_DIM_MAX];

Vector2<int> getCoord(int i)
{
   return Vector2<int>(i%MAP_DIM_MAX, i/MAP_DIM_MAX);
}

Vector2<float> getPixCoordFromGrid(int i, int j, int a=0, int b=0)
{
   return Vector2<float>(x_start+i*TILE_DIM,y_start+j*TILE_DIM);
}

string filename;

void save()
{
   FILE *tosave = fopen(string("../datas/maps/"+filename).c_str(), "w+");

   for(int i = 0 ; i < MAP_DIM_MAX ; i++)
   {
      for(int j = 0 ; j < MAP_DIM_MAX ; j++)
         fprintf(tosave,"%d ",m_map[L_SOL][i][j].second);
      fprintf(tosave,"\n");
   }

   fclose(tosave);
}

vector<Sprite> tile_usable;

void load()
{
   printf("File to load in ../datas/maps/ or q :");
   char fl[100];
   scanf("%s",fl);
   string fls = fl;

   if(fls == "q")
      return;

   FILE *toload = fopen(string("../datas/maps/"+fls).c_str(), "r");

   if(!toload)
   {
      printf("Unable to load %s !\n", string("../datas/maps/"+fls).c_str());
      return;
   }

   for(int i = 0 ; i < MAP_DIM_MAX ; i++)
      for(int j = 0 ; j < MAP_DIM_MAX ; j++)
      {
         int k;
         fscanf(toload,"%d",&k);
         m_map[L_SOL][i][j].first = tile_usable[k];
         m_map[L_SOL][i][j].first.SetPosition(x_start+i*TILE_DIM, y_start+j*TILE_DIM);
         m_map[L_SOL][i][j].second = k;
      }

   fclose(toload);
}

int main()
{
   /*Main Window Creation*/ 
   RenderWindow App(VideoMode(400+MAP_DIM_MAX*TILE_DIM,MAP_DIM_MAX*TILE_DIM+50), "Tower Defense - map editor");

   /*File for S*/
   filename="";

   /*Loading tileset list*/
   char tileset_addr[100];
   FILE *ts_list = fopen("tilesets.list", "r");//On travaille avec 1 seul tileset pour l'instant
   fscanf(ts_list, "%s", tileset_addr);

   /*Main Tileset Loading*/
   Image ts;
   ts.LoadFromFile(tileset_addr);
   ts.CreateMaskFromColor(ts.GetPixel(0,0),0);//transparence du blanc

   /*Cutting the tileset*/

   for(int i = 0 ; i < (int)ts.GetHeight()/TILE_DIM ; i++)
      for(int j = 0 ; j < (int)ts.GetWidth()/TILE_DIM ; j++)
      {
         Sprite curr;
         curr.SetImage(ts);
         curr.SetPosition(j*(TILE_DIM+ESPACE_TS), i*(TILE_DIM+ESPACE_TS));
         curr.SetSubRect(IntRect(j*TILE_DIM+1,i*TILE_DIM+1,j*TILE_DIM+TILE_DIM,i*TILE_DIM+TILE_DIM));
         tile_usable.push_back(curr);
      }

   /*Separating line*/
   Shape sep = Shape::Line(tile_usable[tile_usable.size()-1].GetPosition().x+TILE_DIM+15,0,tile_usable[tile_usable.size()-1].GetPosition().x+TILE_DIM+15,MAP_DIM_MAX*TILE_DIM+50,10,Color::Blue);

   x_start = tile_usable[tile_usable.size()-1].GetPosition().x + 2*TILE_DIM;
   y_start = 10;

   vector<Shape> grille;

   for(int i = 0 ; i <= MAP_DIM_MAX ; i++)
      grille.push_back(Shape::Line(x_start+(TILE_DIM)*i,y_start,x_start+(TILE_DIM)*i,y_start+(TILE_DIM)*MAP_DIM_MAX,EP_LIG,Color::White));
   for(int i = 0 ; i <= MAP_DIM_MAX ; i++)
      grille.push_back(Shape::Line(x_start,y_start+(TILE_DIM)*i,x_start+(TILE_DIM)*MAP_DIM_MAX,y_start+(TILE_DIM)*i,EP_LIG,Color::White));

   Shape Selection[2];
   Selection[TS_SEL] = Shape::Rectangle(0,0,TILE_DIM,TILE_DIM,Color(255,255,255,0),4,Color::Blue);
   Selection[MAP_SEL] = Shape::Rectangle(0,0,TILE_DIM-EP_LIG,TILE_DIM-EP_LIG,Color(255,255,255,0),EP_LIG,Color::Red);
   Selection[MAP_SEL].SetPosition(x_start+1,y_start+1);
   int onTS = 1;

   int currCase[2];
   currCase[0] = 0;
   currCase[1] = 0;

   Sprite currSelectionMap;

   string layer_name[N_LAYER] = {"Coll", "Sol", "Tour"};
   String layer_name_drawable[N_LAYER];
   Font mainF;
   mainF.LoadFromFile("../datas/fonts/Futured.TTF");

   for(int i = 0 ; i < N_LAYER ; i++)
   {
      layer_name_drawable[i].SetFont(mainF);
      layer_name_drawable[i].SetText(layer_name[i]);
      layer_name_drawable[i].SetColor(Color::White);
      layer_name_drawable[i].SetSize(30);
      float largeur = layer_name_drawable[i].GetRect().Right-layer_name_drawable[i].GetRect().Left;
      layer_name_drawable[i].SetPosition((((NB_MAX_PER_LIG*(TILE_DIM+ESPACE_TS)))-largeur)/2,ts.GetHeight()+(ts.GetHeight()/TILE_DIM)*ESPACE_TS);
   }

   const int nbLeg = 6;

   string leg[nbLeg] = {"Changer de layer : L", "Poser un tile : ENTER", "Passer du tileset à la map : TAB", "Remplir le terrain : CTRL+F", 
      "Charger une map : C", "Sauvegarder la map : S"};
   String leg_drawable[nbLeg];

   for(int i = 0 ; i < nbLeg ; i++)
   {
      leg_drawable[i].SetFont(mainF);
      leg_drawable[i].SetText(leg[i]);
      leg_drawable[i].SetColor(Color::Green);
      leg_drawable[i].SetSize(20);
      float largeur = leg_drawable[i].GetRect().Right-leg_drawable[i].GetRect().Left;
      leg_drawable[i].SetPosition((((NB_MAX_PER_LIG*(TILE_DIM+ESPACE_TS)))-largeur)/2,ts.GetHeight()+(ts.GetHeight()/TILE_DIM)*ESPACE_TS+(i+1)*(35));
   }

   while(App.IsOpened())
   {
      int borneDroite, borneGauche = 0, borneHaut = 0, borneBas, nbPerLig;
      int k = 0;
      if(onTS)
      {
         k = ESPACE_TS;
         borneDroite = NB_MAX_PER_LIG*(TILE_DIM+k);
         borneBas = ts.GetHeight()+((ts.GetHeight()/TILE_DIM)*k);
         nbPerLig = NB_MAX_PER_LIG;
      }
      else
      {
         borneDroite = x_start+TILE_DIM*MAP_DIM_MAX;
         borneGauche = x_start;
         borneHaut = y_start;
         borneBas = y_start+TILE_DIM*MAP_DIM_MAX;
         nbPerLig = MAP_DIM_MAX;
      }

      Event event;
      while(App.GetEvent(event))
      {
         switch(event.Type)
         {
            case Event::Closed:
               App.Close();
               break;
            case Event::KeyPressed:
               switch(event.Key.Code)
               {
                  case Key::Right:
                     if(Selection[onTS].GetPosition().x+TILE_DIM+k < borneDroite)
                     {
                        Selection[onTS].Move(TILE_DIM+k,0);
                        currCase[onTS]++;
                     }
                     break;
                  case Key::Left:
                     if(Selection[onTS].GetPosition().x-(TILE_DIM+k) >= borneGauche)
                     {
                        Selection[onTS].Move(-(TILE_DIM+k),0);
                        currCase[onTS]--;
                     }
                     break;
                  case Key::Up:
                     if(Selection[onTS].GetPosition().y-(TILE_DIM+k) >= borneHaut)
                     {
                        Selection[onTS].Move(0,-(TILE_DIM+k));
                        currCase[onTS] -= nbPerLig;
                     }
                     break;
                  case Key::Down:
                     if(Selection[onTS].GetPosition().y+TILE_DIM+k < borneBas)
                     {
                        Selection[onTS].Move(0,TILE_DIM+k);
                        currCase[onTS] += nbPerLig;
                     }
                     break;

                  case Key::Tab:
                     onTS = !onTS;
                     currSelectionMap = tile_usable[currCase[TS_SEL]];
                     break;

                  case Key::F:
                     if(event.Key.Control)
                        for(int i = 0 ; i < MAP_DIM_MAX ; i++)
                           for(int j = 0 ; j < MAP_DIM_MAX ; j++)
                           {
                              m_map[currLayer][i][j] = make_pair(currSelectionMap,currCase[TS_SEL]);
                              m_map[currLayer][i][j].first.SetPosition(getPixCoordFromGrid(i,j,x_start,y_start));  
                           }
                     break;

                  case Key::L:
                     currLayer++;
                     currLayer %= N_LAYER;
                     break;

                  case Key::S:
                     if(filename == "" || event.Key.Control)
                     {
                        char fn[100];
                        printf("Filename in ../datas/maps/ : ");
                        scanf("%s",fn);
                        filename = fn;
                     }

                     save();
                     printf("File Saved at %s\n", filename.c_str());
                     break;

                  case Key::C:
                     load();
                     break;

                  case Key::Return:
                     if(!onTS)
                     {
                        m_map[currLayer][getCoord(currCase[MAP_SEL]).x][getCoord(currCase[MAP_SEL]).y].first = currSelectionMap;
                        m_map[currLayer][getCoord(currCase[MAP_SEL]).x][getCoord(currCase[MAP_SEL]).y].second = currCase[TS_SEL];
                     }
                     else
                     {
                        onTS = !onTS;
                        currSelectionMap = tile_usable[currCase[TS_SEL]];
                     }
                     break;
               }
               break;
         }
      }

      App.Clear();

      if(currLayer == L_SOL)
         for(int i = 0 ; i < tile_usable.size() ; i++)
            App.Draw(tile_usable[i]);

      App.Draw(layer_name_drawable[currLayer]);

      for(int i = 0 ; i < nbLeg ; i++)
         App.Draw(leg_drawable[i]);

      for(int i = 0 ; i < grille.size() ; i++)
         App.Draw(grille[i]);

      for(int i = 0 ; i < MAP_DIM_MAX ; i++)
         for(int j = 0 ; j < MAP_DIM_MAX ; j++)
            App.Draw(m_map[currLayer][i][j].first);

      if(!onTS)
      {
         currSelectionMap.SetPosition(Selection[MAP_SEL].GetPosition());
         App.Draw(currSelectionMap);
         App.Draw(Selection[TS_SEL]);
      }
      App.Draw(Selection[onTS]);

      App.Draw(sep);
      App.Display();
   }

   fclose(ts_list);
}
